#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
配置管理工具

用于加载和管理不同环境的配置文件
"""

import os
import yaml
from pathlib import Path
from typing import Dict, Any, Optional
from functools import lru_cache

try:
    from dotenv import load_dotenv
except ImportError:
    load_dotenv = None

from .logger import get_logger

logger = get_logger(__name__)


class ConfigManager:
    """
    配置管理器
    
    支持从YAML文件和环境变量加载配置
    """
    
    def __init__(self, config_dir: str = None, env: str = None):
        """
        初始化配置管理器
        
        Args:
            config_dir: 配置文件目录
            env: 环境名称 (development, production, testing)
        """
        self.config_dir = Path(config_dir) if config_dir else Path(__file__).parent.parent / "config"
        self.env = env or os.getenv("ENVIRONMENT", "development")
        self._config = None
        
        # 加载环境变量
        if load_dotenv:
            env_file = Path(".env")
            if env_file.exists():
                load_dotenv(env_file)
                logger.info(f"已加载环境变量文件: {env_file}")
    
    @property
    @lru_cache(maxsize=1)
    def config(self) -> Dict[str, Any]:
        """
        获取配置
        
        Returns:
            Dict: 配置字典
        """
        if self._config is None:
            self._config = self._load_config()
        return self._config
    
    def _load_config(self) -> Dict[str, Any]:
        """
        加载配置文件
        
        Returns:
            Dict: 配置字典
        """
        config_file = self.config_dir / f"{self.env}.yaml"
        
        if not config_file.exists():
            logger.warning(f"配置文件不存在: {config_file}，使用默认配置")
            return self._get_default_config()
        
        try:
            with open(config_file, 'r', encoding='utf-8') as f:
                config = yaml.safe_load(f)
            
            # 替换环境变量
            config = self._replace_env_vars(config)
            
            logger.info(f"已加载配置文件: {config_file}")
            return config
            
        except Exception as e:
            logger.error(f"加载配置文件失败: {e}")
            return self._get_default_config()
    
    def _replace_env_vars(self, obj: Any) -> Any:
        """
        递归替换配置中的环境变量
        
        Args:
            obj: 配置对象
            
        Returns:
            Any: 替换后的配置对象
        """
        if isinstance(obj, dict):
            return {key: self._replace_env_vars(value) for key, value in obj.items()}
        elif isinstance(obj, list):
            return [self._replace_env_vars(item) for item in obj]
        elif isinstance(obj, str):
            return self._replace_env_var_string(obj)
        else:
            return obj
    
    def _replace_env_var_string(self, value: str) -> Any:
        """
        替换字符串中的环境变量
        
        支持格式:
        - ${VAR_NAME}: 必需的环境变量
        - ${VAR_NAME:default_value}: 带默认值的环境变量
        
        Args:
            value: 字符串值
            
        Returns:
            Any: 替换后的值
        """
        if not value.startswith("${") or not value.endswith("}"):
            return value
        
        # 提取变量名和默认值
        var_expr = value[2:-1]  # 去掉 ${ 和 }
        
        if ":" in var_expr:
            var_name, default_value = var_expr.split(":", 1)
        else:
            var_name = var_expr
            default_value = None
        
        # 获取环境变量值
        env_value = os.getenv(var_name, default_value)
        
        if env_value is None:
            raise ValueError(f"必需的环境变量未设置: {var_name}")
        
        # 尝试转换类型
        return self._convert_type(env_value)
    
    def _convert_type(self, value: str) -> Any:
        """
        尝试转换字符串为合适的类型
        
        Args:
            value: 字符串值
            
        Returns:
            Any: 转换后的值
        """
        if value.lower() in ('true', 'false'):
            return value.lower() == 'true'
        
        if value.isdigit():
            return int(value)
        
        try:
            return float(value)
        except ValueError:
            return value
    
    def _get_default_config(self) -> Dict[str, Any]:
        """
        获取默认配置
        
        Returns:
            Dict: 默认配置字典
        """
        return {
            "app": {
                "name": "API Test Demo",
                "version": "1.0.0",
                "debug": True,
                "host": "0.0.0.0",
                "port": 8000
            },
            "logging": {
                "level": "INFO",
                "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
            },
            "api": {
                "prefix": "/api/v1",
                "title": "API Test Demo",
                "version": "1.0.0"
            }
        }
    
    def get(self, key: str, default: Any = None) -> Any:
        """
        获取配置值
        
        Args:
            key: 配置键，支持点号分隔的嵌套键 (如: "app.name")
            default: 默认值
            
        Returns:
            Any: 配置值
        """
        keys = key.split(".")
        value = self.config
        
        try:
            for k in keys:
                value = value[k]
            return value
        except (KeyError, TypeError):
            return default
    
    def set(self, key: str, value: Any) -> None:
        """
        设置配置值
        
        Args:
            key: 配置键，支持点号分隔的嵌套键
            value: 配置值
        """
        keys = key.split(".")
        config = self.config
        
        # 导航到父级字典
        for k in keys[:-1]:
            if k not in config:
                config[k] = {}
            config = config[k]
        
        # 设置值
        config[keys[-1]] = value
    
    def update(self, updates: Dict[str, Any]) -> None:
        """
        批量更新配置
        
        Args:
            updates: 更新的配置字典
        """
        for key, value in updates.items():
            self.set(key, value)
    
    def reload(self) -> None:
        """
        重新加载配置
        """
        self._config = None
        # 清除缓存
        self.config.fget.cache_clear()
        logger.info("配置已重新加载")
    
    def validate_config(self) -> bool:
        """
        验证配置的完整性
        
        Returns:
            bool: 配置是否有效
        """
        required_keys = [
            "app.name",
            "app.version",
            "app.host",
            "app.port",
            "logging.level"
        ]
        
        for key in required_keys:
            if self.get(key) is None:
                logger.error(f"缺少必需的配置项: {key}")
                return False
        
        return True
    
    def get_app_config(self) -> Dict[str, Any]:
        """
        获取应用配置
        
        Returns:
            Dict: 应用配置
        """
        return self.get("app", {})
    
    def get_logging_config(self) -> Dict[str, Any]:
        """
        获取日志配置
        
        Returns:
            Dict: 日志配置
        """
        return self.get("logging", {})
    
    def get_api_config(self) -> Dict[str, Any]:
        """
        获取API配置
        
        Returns:
            Dict: API配置
        """
        return self.get("api", {})
    
    def get_database_config(self) -> Dict[str, Any]:
        """
        获取数据库配置
        
        Returns:
            Dict: 数据库配置
        """
        return self.get("database", {})
    
    def get_redis_config(self) -> Dict[str, Any]:
        """
        获取Redis配置
        
        Returns:
            Dict: Redis配置
        """
        return self.get("redis", {})
    
    def get_external_services_config(self) -> Dict[str, Any]:
        """
        获取外部服务配置
        
        Returns:
            Dict: 外部服务配置
        """
        return self.get("external_services", {})
    
    def is_development(self) -> bool:
        """
        是否为开发环境
        
        Returns:
            bool: 是否为开发环境
        """
        return self.env == "development"
    
    def is_production(self) -> bool:
        """
        是否为生产环境
        
        Returns:
            bool: 是否为生产环境
        """
        return self.env == "production"
    
    def is_testing(self) -> bool:
        """
        是否为测试环境
        
        Returns:
            bool: 是否为测试环境
        """
        return self.env == "testing"
    
    def __str__(self) -> str:
        """
        字符串表示
        
        Returns:
            str: 配置管理器描述
        """
        return f"ConfigManager(env={self.env}, config_dir={self.config_dir})"
    
    def __repr__(self) -> str:
        """
        对象表示
        
        Returns:
            str: 配置管理器表示
        """
        return self.__str__()


# 全局配置管理器实例
_config_manager = None


def get_config_manager(config_dir: str = None, env: str = None) -> ConfigManager:
    """
    获取配置管理器实例（单例模式）
    
    Args:
        config_dir: 配置文件目录
        env: 环境名称
        
    Returns:
        ConfigManager: 配置管理器实例
    """
    global _config_manager
    
    if _config_manager is None:
        _config_manager = ConfigManager(config_dir, env)
    
    return _config_manager


def get_config(key: str = None, default: Any = None) -> Any:
    """
    获取配置值的便捷函数
    
    Args:
        key: 配置键
        default: 默认值
        
    Returns:
        Any: 配置值
    """
    config_manager = get_config_manager()
    
    if key is None:
        return config_manager.config
    
    return config_manager.get(key, default)


def reload_config() -> None:
    """
    重新加载配置的便捷函数
    """
    config_manager = get_config_manager()
    config_manager.reload()


# 导出常用配置获取函数
def get_app_config() -> Dict[str, Any]:
    """获取应用配置"""
    return get_config_manager().get_app_config()


def get_logging_config() -> Dict[str, Any]:
    """获取日志配置"""
    return get_config_manager().get_logging_config()


def get_api_config() -> Dict[str, Any]:
    """获取API配置"""
    return get_config_manager().get_api_config()


def get_database_config() -> Dict[str, Any]:
    """获取数据库配置"""
    return get_config_manager().get_database_config()


def get_redis_config() -> Dict[str, Any]:
    """获取Redis配置"""
    return get_config_manager().get_redis_config()


def get_external_services_config() -> Dict[str, Any]:
    """获取外部服务配置"""
    return get_config_manager().get_external_services_config()